package cn.zurish.cloud.security.service;

import cn.zurish.cloud.security.dao.entity.SysRole;
import cn.zurish.cloud.security.dao.entity.SysUser;
import cn.zurish.cloud.security.dao.entity.SysUserAttr;
import cn.zurish.cloud.security.dao.mapper.RoleMapper;
import cn.zurish.cloud.security.dao.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {

    private final UserMapper userMapper;
    private final RoleMapper roleMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        // 1. 查询基础用户信息
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, username);
        SysUser user = userMapper.selectOne(wrapper);

        if (user == null) {
            throw new UsernameNotFoundException("用户不存在");
        }

        // 2. 加载角色和权限
        List<SysRole> roles = userMapper.selectRolesByUserId(user.getUserId());
        roles.forEach(role ->
                role.setMenus(roleMapper.selectMenusByRoleId(role.getRoleId()))
        );
        user.setRoles(roles);

        // 3. 检查账户状态
        if (!user.isEnabled()) {
            throw new DisabledException("用户已被禁用");
        }

        // 4. 用户的属性集合，用于 ABAC 动态权限评估
        List<SysUserAttr> attrs = userMapper.selectUserAttrByUserId(user.getUserId());
        // 转成map集合
        user.setAttrs(attrs.stream()
                .collect(Collectors.toMap(s -> s.getAttrKey(), s -> s.getAttrValue())));
        return user;
    }
}
